﻿using System;
using System.Xml.Linq;

namespace SharePoint.Orm.Caml {
	public class CamlLogicalOp : CamlExpr {
		private readonly CamlLogicalOpType _op;
		public CamlExpr First { get; set; }
		public CamlExpr Second { get; set; }

		public CamlLogicalOpType Op {
			get { return _op; }
		}

		public CamlLogicalOp(CamlLogicalOpType op) {
			_op = op;
		}

		public CamlLogicalOp(CamlLogicalOpType op, CamlExpr first, CamlExpr second) {
			_op = op;
			First = first;
			Second = second;
		}

		public override string ToString() {
			return ToXml().ToString();
		}

		public override XObject ToXml() {
			XElement andElement = new XElement(LogicalOperatorString(_op));
			andElement.Add(First.ToXml());
			andElement.Add(Second.ToXml());
			return andElement;
		}

		private static string LogicalOperatorString(CamlLogicalOpType op) {
			switch (op) {
				case CamlLogicalOpType.And:
					return "And";
				case CamlLogicalOpType.Or:
					return "Or";
				default:
					return "";
			}
		}

		public static bool IsLogicalOp(XElement element) {
			return ParseOp(element.Name.ToString()) != null;
		}

		public static CamlLogicalOpType? ParseOp(string op) {
			switch (op) {
				case "And":
					return CamlLogicalOpType.And;
				case "Or":
					return CamlLogicalOpType.Or;
			}
			return null;
		}

		public static CamlLogicalOp Parse(XElement element) {
			CamlLogicalOp result = new CamlLogicalOp(ParseOp(element.Name.ToString()).Value);
			int count = 0;
			foreach (XElement child in element.Elements()) {
				if (count == 0) {
					result.First = CamlExpr.Parse(child);
				} else if (count == 1) {
					result.Second = CamlExpr.Parse(child);
				} else {
					throw new Exception("Unexpected element '" + child.Name + "'");
				}
				count++;
			}
			return result;
		}
	}

	public class CamlAnd : CamlLogicalOp {
		public CamlAnd()
			: base(CamlLogicalOpType.And) {

		}

		public CamlAnd(CamlExpr first, CamlExpr second)
			: base(CamlLogicalOpType.And, first, second) {
		}
	}

	public class CamlOr : CamlLogicalOp {
		public CamlOr()
			: base(CamlLogicalOpType.Or) {

		}

		public CamlOr(CamlExpr first, CamlExpr second)
			: base(CamlLogicalOpType.Or, first, second) {
		}
	}
}
